from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles
from fastapi.responses import FileResponse
from sqlalchemy.orm import Session
from jose import JWTError, jwt
from passlib.context import CryptContext
from datetime import datetime, timedelta
from typing import List, Optional  # 添加这行
import uvicorn
import models, schemas, database

# 创建数据库表
models.Base.metadata.create_all(bind=database.engine)

app = FastAPI(title="Shopping Website API")
# app.mount("/static", StaticFiles(directory="../frontend/static/"), name="static")

# 静态文件服务（包含前端页面）
app.mount("/", StaticFiles(directory="../frontend", html=True), name="static")

# CORS配置
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# 密码加密
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")

# JWT配置
SECRET_KEY = "your-secret-key-change-this-in-production"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

def verify_password(plain_password, hashed_password):
    return pwd_context.verify(plain_password, hashed_password)

def get_password_hash(password):
    return pwd_context.hash(password)

def authenticate_user(db: Session, username: str, password: str):
    user = db.query(models.User).filter(models.User.username == username).first()
    if not user:
        return False
    if not verify_password(password, user.hashed_password):
        return False
    return user

def create_access_token(data: dict, expires_delta: timedelta = None):
    to_encode = data.copy()
    if expires_delta:
        expire = datetime.utcnow() + expires_delta
    else:
        expire = datetime.utcnow() + timedelta(minutes=15)
    to_encode.update({"exp": expire})
    encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
    return encoded_jwt


def get_current_user(token: str = Depends(oauth2_scheme), db: Session = Depends(database.get_db)):
    credentials_exception = HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="Could not validate credentials",
        headers={"WWW-Authenticate": "Bearer"},
    )
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        username: str = payload.get("sub")
        if username is None:
            raise credentials_exception
        token_data = schemas.TokenData(username=username)
    except JWTError:
        raise credentials_exception
    user = db.query(models.User).filter(models.User.username == token_data.username).first()
    if user is None:
        raise credentials_exception
    return user

def get_current_admin(current_user: models.User = Depends(get_current_user)):
    """验证当前用户是否为管理员"""
    if not current_user.is_admin:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Insufficient permissions (requires admin)"
        )
    return current_user


@app.get("/auth/user", response_model=schemas.User)
def read_users_me(current_user: models.User = Depends(get_current_user)):
    return current_user

@app.post("/users/", response_model=schemas.User)
def create_user(user: schemas.UserCreate, db: Session = Depends(database.get_db)):
    db_user = db.query(models.User).filter(
        (models.User.username == user.username) | 
        (models.User.email == user.email)
    ).first()
    if db_user:
        raise HTTPException(status_code=400, detail="Username or email already registered")
    hashed_password = get_password_hash(user.password)
    db_user = models.User(
        username=user.username,
        email=user.email,
        is_admin=False,  # 默认普通用户
        hashed_password=hashed_password
    )
    db.add(db_user)
    db.commit()
    db.refresh(db_user)
    return db_user

@app.post("/token", response_model=schemas.Token)
def login_for_access_token(form_data: OAuth2PasswordRequestForm = Depends(), db: Session = Depends(database.get_db)):
    user = authenticate_user(db, form_data.username, form_data.password)
    if not user:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Incorrect username or password",
            headers={"WWW-Authenticate": "Bearer"},
        )
    access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
    access_token = create_access_token(
        data={"sub": user.username}, expires_delta=access_token_expires
    )
    return {"access_token": access_token, "token_type": "bearer"}

@app.get("/products/", response_model=List[schemas.Product])  # 修改这里
def read_products(skip: int = 0, limit: int = 100, db: Session = Depends(database.get_db)):
    products = db.query(models.Product).offset(skip).limit(limit).all()
    return products

@app.post("/products/", response_model=schemas.Product)
def create_product(product: schemas.ProductCreate, db: Session = Depends(database.get_db)):
    db_product = models.Product(**product.dict())
    db.add(db_product)
    db.commit()
    db.refresh(db_product)
    return db_product

@app.get("/cart/", response_model=schemas.CartResponse)
def get_cart(
    current_user: models.User = Depends(get_current_user),  # 验证登录用户
    db: Session = Depends(database.get_db)  # 获取数据库连接
):
    """
    获取当前登录用户的购物车数据
    - 前端通过GET /cart/请求，携带Bearer Token
    - 返回格式包含items字段，每个项包含商品详情
    """
    # 查询当前用户的所有购物车项，并关联商品信息
    cart_items = db.query(models.CartItem).filter(models.CartItem.user_id == current_user.id).all()
    
    # 返回包含items字段的响应（与前端cartData.items对应）
    return {"items": cart_items}

@app.post("/cart/", response_model=List[schemas.CartItem])
def add_multiple_to_cart(
    cart_data: schemas.CartItemList,  # 接收包含items数组的请求体
    current_user: models.User = Depends(get_current_user), 
    db: Session = Depends(database.get_db)
):
    result = []
    for item in cart_data.items:
        # 检查商品是否存在
        product = db.query(models.Product).filter(models.Product.id == item.product_id).first()
        if not product:
            raise HTTPException(status_code=404, detail=f"Product with id {item.product_id} not found")
        
        # 检查库存
        if product.stock < item.quantity:
            raise HTTPException(status_code=400, detail=f"Not enough stock for product {product.name}")
        
        # 检查是否已存在购物车项
        existing_item = db.query(models.CartItem).filter(
            models.CartItem.user_id == current_user.id,
            models.CartItem.product_id == item.product_id
        ).first()
        
        if existing_item:
            existing_item.quantity += item.quantity
            db.refresh(existing_item)
            result.append(existing_item)
        else:
            db_cart_item = models.CartItem(
                user_id=current_user.id,
                product_id=item.product_id,
                quantity=item.quantity
            )
            db.add(db_cart_item)
            db.commit()
            db.refresh(db_cart_item)
            result.append(db_cart_item)
    
    db.commit()  # 统一提交事务
    return result

@app.delete("/cart/{cart_item_id}")
def remove_from_cart(cart_item_id: int, current_user: models.User = Depends(get_current_user), db: Session = Depends(database.get_db)):
    cart_item = db.query(models.CartItem).filter(
        models.CartItem.id == cart_item_id,
        models.CartItem.user_id == current_user.id
    ).first()
    if not cart_item:
        raise HTTPException(status_code=404, detail="Cart item not found")
    db.delete(cart_item)
    db.commit()
    return {"message": "Item removed from cart"}

@app.get("/")
async def get():
    return FileResponse("index.html")

# 初始化一些示例数据
@app.on_event("startup")
def startup_event():
    db = database.SessionLocal()
    try:
        # 检查是否已有商品
        if db.query(models.Product).count() == 0:
            products = [
                models.Product(name="iPhone 15", description="Latest Apple iPhone", price=4999.99, image_url="https://placehold.co/300x300/007AFF/white?text=iPhone", stock=50, category="电子产品", is_new=True, is_hot=True),
                models.Product(name="Samsung Galaxy S24", description="Premium Android smartphone", price=3899.99, image_url="https://placehold.co/300x300/1428A0/white?text=Samsung", stock=30, category="电子产品", is_new=True),
                models.Product(name="MacBook Pro", description="Professional laptop for developers", price=6499.99, image_url="https://placehold.co/300x300/000000/white?text=MacBook", stock=20, category="服装鞋帽", is_hot=True),
                models.Product(name="iPad Air", description="Versatile tablet for work and play", price=599.99, image_url="https://placehold.co/300x300/007AFF/white?text=iPad", stock=40, category="服装鞋帽", is_new=True),
                models.Product(name="AirPods Pro", description="Wireless earbuds with noise cancellation", price=249.99, image_url="https://placehold.co/300x300/FFFFFF/black?text=AirPods", stock=100, category="家居用品", is_hot=True),
                models.Product(name="Huawei Watch", description="Smartwatch with health features", price=399.99, image_url="https://placehold.co/300x300/000000/white?text=Watch", stock=60, category="家居用品", is_new=True),
            ]
            for product in products:
                db.add(product)
            db.commit()

        # 初始化管理员账户（如果不存在）
        if not db.query(models.User).filter(models.User.username == "admin").first():
            admin = models.User(
                username="admin",
                email="admin@example.com",
                hashed_password=get_password_hash("admin123"),  # 生产环境需修改密码
                is_admin=True
            )
            db.add(admin)
            db.commit()

    finally:
        db.close()

# ------------------------------
# 启动服务
# ------------------------------
if __name__ == "__main__":
    uvicorn.run("main:app", host="192.168.10.124", port=8000, reload=True)   